﻿using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using MVCms.Core.DataAccess;
using MVCms.Core.Developers;
using MVCms.Core.Entities;


namespace MVCms.Core.Services
{
    public static class PluginService
    {
        /// <summary>
        /// Saves the specified plugin.
        /// </summary>
        /// <param name="plugin">The plugin.</param>
        public static void Save(this Entities.Plugin plugin)
        {
            McContext.Save(plugin);
        }

        /// <summary>
        /// Gets all the modules.
        /// </summary>
        /// <returns></returns>
        public static List<Entities.PluginModule> GetModules()
        {
            return McContext.Load<Entities.PluginModule>().ToList();
        }

        /// <summary>
        /// Gets the module based on it's fullname.
        /// </summary>
        /// <param name="moduleFullName">Full name of the module.</param>
        /// <returns></returns>
        public static Entities.PluginModule GetModule(string moduleFullName)
        {
            return McContext.Load<Entities.PluginModule>().Where(m => m.ControllerFullName == moduleFullName).
                    FirstOrDefault();
        }

        /// <summary>
        /// Gets the module based on it's id.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns></returns>
        public static Entities.PluginModule GetModule(int id)
        {
            return McContext.Load<Entities.PluginModule>().Where(m => m.Id == id).
                    FirstOrDefault();
        }

        /// <summary>
        /// Gets the module based on it's controller - action.
        /// </summary>
        /// <param name="controller">The controller.</param>
        /// <param name="action">The action.</param>
        /// <returns></returns>
        public static Entities.PluginModule GetModule(string controller, string action)
        {
            return McContext.Load<Entities.PluginModule>().Where(m => m.Action == action && m.Controller == controller).
                    FirstOrDefault();
        }

        /// <summary>
        /// Gets the plugin modules the specified dll.
        /// </summary>
        /// <param name="plugin">The plugin.</param>
        /// <param name="fileInfo">The file info.</param>
        /// <returns></returns>
        public static IList<PluginModule> GetPluginModules(Plugin plugin, FileInfo fileInfo)
        {
            var modules = new List<PluginModule>();

            //get all plugin files
            if (fileInfo.Name.StartsWith("Plugin"))
            {
                var assemblyBytes = File.ReadAllBytes(fileInfo.FullName);
                var assembly = Assembly.Load(assemblyBytes);

                //Get Methods
                var methods = assembly.GetTypes().SelectMany(t => t.GetMethods())
                    .Where(m => m.GetCustomAttributes(typeof(PluginModuleAttribute), false).Length > 0)
                    .ToArray();

                // get info from the decorated attribute
                foreach (MethodInfo methodInfo in methods)
                {
                    var controlerfullName = methodInfo.DeclaringType.FullName.Split('.');
                    var controller = controlerfullName[controlerfullName.Count() - 1].Replace("Controller", null);
                    object[] attributes = methodInfo.GetCustomAttributes(true);
                    string postToAction = string.Empty;
                    string postToController = string.Empty;
                    string name = string.Empty;
                    string description = string.Empty;
                    foreach (object attribute in attributes)
                    {
                        PluginModuleAttribute pa = attribute as PluginModuleAttribute;
                        if (pa != null)
                        {
                            postToAction = pa.PostAction;
                            postToController = pa.PostController;
                            name = pa.Name;
                            description = pa.Description;
                        }
                    }

                    // fill the info and add the module
                    modules.Add(new PluginModule
                    {
                        Action = methodInfo.Name,
                        ControllerFullName = methodInfo.DeclaringType.FullName,
                        Controller = controller,
                        Plugin = plugin,
                        PostController = postToController,
                        PostAction = postToAction,
                        Name = name,
                        Description = description
                        
                    });
                }
            }

            return modules;
        }
    }
}
